import subprocess
import re
import pprint
import os
import urllib2
import sys
import datetime
from datetime import date
import time
import sys

from psn_game import psnGame
from psn_web import psnWeb
from psn_django import *

import Levenshtein
import traceback

psn_game = psnGame()

def user_compare(user_a, user_b):

	if int(user_a.points) != int(user_b.points):
		return int(user_a.points - user_b.points)

	if int(user_a.platinum) != int(user_b.platinum):
		return int(user_a.platinum - user_b.platinum)

	if int(user_a.gold) != int(user_b.gold):
		return int(user_a.gold - user_b.gold)

	if int(user_a.silver) != int(user_b.silver):
		return int(user_a.silver - user_b.silver)

	if int(user_a.bronze) != int(user_b.bronze):
		return int(user_a.bronze - user_b.bronze)

	return 0

def recalcRank():

	#users_db = db.userTrophy.objects.order_by('-points')

	users_db = list(db.userTrophy.objects.all())
	users_db.sort(user_compare, reverse=True)

	i = 0

	for user in users_db:
		i += 1
		user.rank = i
		user.save()
	
		if user.last_trophy.rank == 0:
			user.last_trophy.rank = user.rank
			user.last_trophy.save()

		print "%d - %s" %(i, user.user.auth.username)

def getUser(user):
	# Cria o modelo para a tabela do usuario
	# referente a lista de jogos

	# Primeiro precisamos de um usuario padrao no sistema
	# este usuario eh oq eh cadastrado pela tela de Sign Up
	user_auth_db = User.objects.filter(username=user["psn_id"])

	if len(user_auth_db) is 0:
		print "New USER : %s " %user["psn_id"]

		user_auth_db  = User.objects.create_user(user["psn_id"], 'fabriciols@itautec.com', 'rootroot')
		user_auth_db.save()

	else:
		user_auth_db = user_auth_db[0]

	# Depois precisamos de uma entrada neste usuario
	# com mais informacoes, eh aqui que indica se o usuario
	# ja esta no rank ou nao
	user_db = db.userInfo.objects.filter(auth=user_auth_db)

	if len(user_db) is 0:
		print "New USER INFO (%s)" %user["psn_id"]

		user_db       = db.userInfo(auth = user_auth_db,
										 pic_url = user["pic_url"])
		user_db.save()
	else:
		user_db = user_db[0]
		# Se ja for cadastrado, atualiza o avatar dele
		user_db.pic_url = user["pic_url"]
		user_db.save()

	return user_db


def createLastGameInfo(user_game_db):
	user_last_game_db = db.userLastGameInfo.objects.filter(
		game      = user_game_db.game,
		user      = user_game_db.user,
		platinum  = user_game_db.platinum,
		gold      = user_game_db.gold,
		silver    = user_game_db.silver,
		bronze    = user_game_db.bronze,
		total     = user_game_db.total,
		perc_done = user_game_db.perc_done)

	if len(user_last_game_db) is not 0:
		user_last_game_db = user_last_game_db[0]

		print "Not creating a new last game entry"

		# So atualizo a data
		user_last_game_db.date_update = user_game_db.date_update

		return user_last_game_db

	user_last_game_db = db.userLastGameInfo(
		game    = user_game_db.game,
		user    = user_game_db.user,
		platinum= user_game_db.platinum,
		gold    = user_game_db.gold,
		silver  = user_game_db.silver,
		bronze  = user_game_db.bronze,
		total   = user_game_db.total,
		perc_done   = user_game_db.perc_done,
		date_update = user_game_db.date_update)

	return user_last_game_db

def createLastTrophy(userTrophy_db):
	last_trophy_db = db.userLastTrophy.objects.filter(
		user     = userTrophy_db.user,
		platinum = userTrophy_db.platinum,
		gold  = userTrophy_db.gold,
		silver= userTrophy_db.silver,
		bronze= userTrophy_db.bronze,
		level = userTrophy_db.level,
		total = userTrophy_db.total,
		points= userTrophy_db.points,
		rank  = userTrophy_db.rank,
		perc_level  = userTrophy_db.perc_level)

	if len(last_trophy_db) is not 0:
		last_trophy_db = last_trophy_db[0]

		print "Not creating a new last user entry"

		# So atualizo a data
		last_trophy_db.date_update = userTrophy_db.date_update
		last_trophy_db.save()

		return last_trophy_db

	last_trophy_db = db.userLastTrophy(
		user     = userTrophy_db.user,
		platinum = userTrophy_db.platinum,
		gold  = userTrophy_db.gold,
		silver= userTrophy_db.silver,
		bronze= userTrophy_db.bronze,
		level = userTrophy_db.level,
		total = userTrophy_db.total,
		points= userTrophy_db.points,
		rank  = userTrophy_db.rank,
		perc_level  = userTrophy_db.perc_level,
		date_update = userTrophy_db.date_update)

	last_trophy_db.save()

	return last_trophy_db

def updateUserTrophy(user_db, user_info, updateType):

	userTrophy_db = db.userTrophy.objects.filter(user=user_db)

	new = False

	if len(userTrophy_db) is 0:
		# Se o usuario eh novo, vamos atribiu o last = atual
		print "New trophy info for user: %s" %user_info["psn_id"]

		userTrophy_db = db.userTrophy(
										user       = user_db,
										platinum   = user_info["platinum"],
										gold       = user_info["gold"],
										silver     = user_info["silver"],
										bronze     = user_info["bronze"],
										level      = user_info["level"],
										perc_level = user_info["perc_level"])
		
		last_trophy_db = createLastTrophy(userTrophy_db)
		userTrophy_db.last_trophy = last_trophy_db
		userTrophy_db.save()

		new = True
	
	else:

		userTrophy_db = userTrophy_db[0]

		# Se a atualizacao for MAJOR
		# atribuimos :
		# last    vira MAJOR;
		# major   vira ATUAL;
		if updateType == MAJOR:
			print "Update %s in user %s" %(updateType, user_info["psn_id"])
			last_trophy_db = createLastTrophy(userTrophy_db)
			userTrophy_db.last_trophy = last_trophy_db

		# Se for PARTIAL atualizamos so o valor total
		elif updateType == PARTIAL:
			print "Update %s in user %s" %(updateType, user_info["psn_id"])

		userTrophy_db.platinum   = user_info["platinum"]
		userTrophy_db.gold       = user_info["gold"]
		userTrophy_db.silver     = user_info["silver"]
		userTrophy_db.bronze     = user_info["bronze"]
		userTrophy_db.level      = user_info["level"]
		userTrophy_db.perc_level = user_info["perc_level"]
		userTrophy_db.date_update = datetime.datetime.now()

		userTrophy_db.save()

	return userTrophy_db, new

def updateUserGameList(user_db, game_db, game, updateType):

	new = False

	user_game_db = db.userGameInfo.objects.filter(user=user_db, game=game_db)

	if len(user_game_db) is 0:
		print "New game (%s) for user %s" %(game["psn_id"], user_db.auth.username)

		user_game_db = db.userGameInfo(
			user    = user_db,
			game    = game_db,
			perc_done = game["perc_done"],
			platinum  = game["platinum"],
			gold      = game["gold"],
			silver	 = game["silver"],
			bronze    = game["bronze"])

		user_last_game_db = createLastGameInfo(user_game_db)
		user_last_game_db.save()

		user_game_db.last = user_last_game_db
		user_game_db.save()

		new = True

	else:
		user_game_db = user_game_db[0]

	if updateType == MAJOR:

		user_last_game_db = createLastGameInfo(user_game_db)

		# Salvamos esta nova entrada
		user_last_game_db.save()

		# Atualiza a referencia para o novo last
		user_game_db.last = user_last_game_db
		user_game_db.save()

	# Se for PARTIAL atualizamos so o valor total
	elif updateType == PARTIAL:
		pass

	i=0

	# Atualizar o principal ocorre independente se for partial ou major
	if user_game_db.platinum != int(game["platinum"]):
		user_game_db.platinum  =  game["platinum"]
		i += 1

	if user_game_db.gold != int(game["gold"]):
		user_game_db.gold =  game["gold"]
		i += 1

	if user_game_db.silver != int(game["silver"]):
		user_game_db.silver =  game["silver"]
		i += 1

	if user_game_db.bronze != int(game["bronze"]):
		user_game_db.bronze =  game["bronze"]
		i += 1

	if user_game_db.perc_done != int(game["perc_done"]):
		user_game_db.perc_done  = game["perc_done"]
		i += 1

	user_game_db.date_update = datetime.datetime.now()
	user_game_db.save()

	return user_game_db, new, i

def updateUserGameInfo(user_db, game_db, GAME_TROPHY_LIST):
	j=0
	k=1
	l=1
	hidden = 0
	for TROPHY in GAME_TROPHY_LIST:
		j += 1
		if TROPHY.has_key('id'):
			hidden = 0
			trophy = TROPHY["id"]
		else:
			if TROPHY["type"] == "HIDDEN":
				name = "Hidden id(%d)" %j
				detail = "Hidden Trophy"

				hidden = k
				trophy = 0
				k += 1
			else:
				name = TROPHY["name"]
				detail = TROPHY["desc"]

				hidden = 0
				trophy = l
				l += 1

		game_trophy_info_db = db.gameTrophyInfo.objects.filter(game=game_db, trophy_id=trophy, hidden_id=hidden)

		if len(game_trophy_info_db) is 0:
			if re.match('[0-9]*', game_db.psn_id):
				psn_game.newGameTropy(game_db, [TROPHY], force=True, j=j)
			else:
				print "Problem with game: %s" %game_db.psn_id
				fixGame(user_db, game_db)
	
			# Refaz a query
			game_trophy_info_db = db.gameTrophyInfo.objects.filter(game=game_db, trophy_id=trophy, hidden_id=hidden)
			
			if len(game_trophy_info_db) is 0:
				print "FAIL"
				print game_db.psn_id, trophy, hidden
				raise Exception

			game_trophy_info_db = game_trophy_info_db[0]
		else:
			game_trophy_info_db = game_trophy_info_db[0]

		if TROPHY.has_key("date"):
			game_user_trophy_info_db = db.gameUserTrophyInfo.objects.filter(trophy=game_trophy_info_db, user=user_db)

			if TROPHY.has_key("id"):
				# Exemplo de data 'Thu, 04 Feb 2010 22:10:20 -0800'
				format = '%a, %d %b %Y %H:%M:%S'
				date_adj = re.sub(' [-+][0-9]*', '' , TROPHY["date"])
				date = datetime.datetime(*time.strptime(date_adj, format)[0:5])

			else:
				# Exemplo de data 'Wed Oct 21 18:17:05 PDT 2009',
				year = int(re.sub('(?P<d1>.*:[0-9]{2}) [A-Z]* (?P<d2>[0-9]*)', '\g<d2>', TROPHY["date"]))

				if year < 2000:
					year += 2000

				format = '%a %b %d %H:%M:%S %Y'
				date_adj = re.sub('(?P<d1>.*:[0-9]{2}) [A-Z]* (?P<d2>[0-9]*)', '\g<d1> ' + str(year), TROPHY["date"])
				date = datetime.datetime(*time.strptime(date_adj, format)[0:5])
			
			if len(game_user_trophy_info_db) is 0:

				try:
					print "New User Trophy |%s| |%s| |%s|" %(user_db.auth.username, game_trophy_info_db.game.psn_id, game_trophy_info_db.name)
				except:
					print "Bad char 2"
					pprint.pprint(TROPHY)

				game_user_trophy_info_db = db.gameUserTrophyInfo(
						user = user_db,
						trophy = game_trophy_info_db,
						date = date,
						date_read = TROPHY["date"])

				game_user_trophy_info_db.save()

# 0 - Iguais
# 1 - Diferentes
def compareLastGameInfo(gameInfo_a, gameInfo_b):

	if int(gameInfo_a.platinum)!= int(gameInfo_b.platinum):
		return 1
	elif int(gameInfo_a.gold)  != int(gameInfo_b.gold):
		return 1
	elif int(gameInfo_a.silver)!= int(gameInfo_b.silver):
		return 1
	elif int(gameInfo_a.bronze)!= int(gameInfo_b.bronze):
		return 1

	return 0

def fixGame(user_db, game_db):

	# Precisamos apagar todos os registros de trofeu deste jogo
	# Informacoes proprias
	db.gameTrophyInfo.objects.filter(game=game_db).delete()
	# Informacoes dos users
	db.gameUserTrophyInfo.objects.filter(trophy__game=game_db).delete()

	# Agora nos chamamos o psn_games para povoar a tabela com os dados deste jogo obtidos na psn
	psn_game.fillGamesTrophy(game_db.psn_id, user_db.auth.username)

def compareLastUserInfo(user_a, user_b):

	if   int(user_a.platinum)!= int(user_b.platinum):
		return 1
	elif int(user_a.gold)    != int(user_b.gold):
		return 1
	elif int(user_a.silver)  != int(user_b.silver):
		return 1
	elif int(user_a.bronze)  != int(user_b.bronze):
		return 1

	return 0

import pprint

def removeNonAscii(s): return "".join(i for i in s if ord(i)<128)

def compare_psn_ps3tcard(psn_list, ps3tcard_list):
	GAME_LIST = []
	GAME_LIST_2 = []
	GAME_LIST_PS3TCARD = []

	for game in psn_list:
		game_name = removeNonAscii(game["name"])

		# Tratamento de excessao!
		if game_name == 'GTA IV':
			game_name = 'Grand Theft Auto IV'
		
		# Nao tem na ps3trophycard
		if game_name == 'Army of TWO: The 40th Day':
			continue

		if game_name == 'flOw trophy set':
			game_name = 'fl0w'

		GAME_LIST.append(game_name)
		GAME_LIST_2.append(game_name)

	for game in ps3tcard_list:
		if game["name"] in GAME_LIST:
			GAME_LIST.remove(game["name"])
			GAME_LIST_2.remove(game["name"])
		else:
			GAME_LIST_PS3TCARD.append(game["name"])

	for game_1 in GAME_LIST:
		for game_2 in GAME_LIST_PS3TCARD:	

			game_1_str = game_1.upper()
			game_2_str = game_2.upper()

			ratio = Levenshtein.ratio(game_1_str, game_2_str)
	
			if (ratio > 0.5):
				GAME_LIST_2.remove(game_1)
				GAME_LIST_PS3TCARD.remove(game_2)
				break

	pprint.pprint(GAME_LIST)
	pprint.pprint(GAME_LIST_PS3TCARD)

	if len(GAME_LIST_2) > 0:
		pprint.pprint(psn_list)
		print '-'*100
		pprint.pprint(ps3tcard_list)
		print '-'*100
		pprint.pprint(GAME_LIST_2)
		print '-'*100
		pprint.pprint(GAME_LIST_PS3TCARD)
		print "GAME_LIST_PSN is greater than GAME_LIST_PS3TCARD"
		return []
	else:

		GAME_NEW = []

		for game_1 in GAME_LIST_PS3TCARD:
			for game_2 in ps3tcard_list:
				if game_1 == game_2["name"]:
					GAME_NEW.append(game_2)

		return GAME_NEW

if __name__ == '__main__':

	PARTIAL = "PARTIAL"
	MAJOR   = "MAJOR"
	CARD    = "CARD"
	CARD_MAJOR = CARD + "_" + MAJOR
	CARD_PARTIAL = CARD + "_" + PARTIAL

	psn_web = psnWeb()

	updateType = sys.argv[1]

	try:
		manual = sys.argv[2]
	except:
		manual = False

	USER_LIST = []

	if manual:
		USER_LIST = User.objects.filter(username=manual)
	else:
		USER_LIST = User.objects.all()

	if updateType.startswith(CARD):
		card_updateType = updateType
		updateType = updateType.replace('CARD_', '')
	else:
		card_updateType = ""

	for user_db in USER_LIST:
		print "Update in user |%s|" %user_db.username

		try:

			userID = user_db.username
			USER_INFO      = psn_web.get_user_info(userID)

			# Pega o usuario, se for novo ja cadastra e devolve
			user_db = getUser(USER_INFO)
			GAME_USER_LIST = psn_web.get_user_games_list(userID)

			if card_updateType.startswith(CARD):
				if int(user_db.ps3card) is 1:
					GAME_USER_LIST_PS3TCARD = []
					GAME_NOT_PSN = []

					# Pega a lista de jogos do ps3trophycard e compara
					try:
						print "Get ps3tcard for user |%s|" %(USER_INFO["psn_id"])
						GAME_USER_LIST_PS3TCARD = psn_web.get_games_trophycard(userID, user_db.auth.email)
					except urllib2.URLError:
						print "Fail"

					# Atualiza a URL do card
					if user_db.ps3card_url == "0":
						user_db.ps3card_url = psn_web.ps3trophycard_get_card_url(userID)
						user_db.save()
						print "Update card URL = %s" %user_db.ps3card_url

					# Compara e gera uma lista dos faltantes
					if len(GAME_USER_LIST_PS3TCARD) > 0:
						GAME_NOT_PSN = compare_psn_ps3tcard(GAME_USER_LIST, GAME_USER_LIST_PS3TCARD)

					if len(GAME_NOT_PSN) > 0:
						print "User |%s| has games not in psn:" %userID
						pprint.pprint(GAME_NOT_PSN)

					GAME_USER_LIST = GAME_NOT_PSN
				else:
					continue

			# Atualiza a lista de trofeus do usuario
			userTrophy_db, newUser = updateUserTrophy(user_db, USER_INFO, updateType)

			for game in GAME_USER_LIST:
				# Pega o jogo
				game_db = psn_game.getGame(game, user=user_db.auth.username)

				# Atualiza a lista de jogos do usuario
				try:
					print "Update User Game |%s| - |%s| - |%s| - |START|" %(updateType, user_db.auth.username, game_db.psn_id)
				except:
					print "FUUUUCK"
					print user_game_db.game.id
					pass

				user_game_db, new_user, itens_changed = updateUserGameList(user_db, game_db, game, updateType)

				# Atualiza o trofeu do jogo corrente para o usuario
				# somente se teve trofeu novo, ou se usuario novo
				if itens_changed > 0 or new_user is True:
					GAME_TROPHY_LIST = psn_web.get_user_game_info(userID, game["psn_id"])

					try:
						updateUserGameInfo(user_db, game_db, GAME_TROPHY_LIST)
					except:
						print "Update FAIL Game |%s| - |%s| - |%s| - |END|" %(updateType, user_db.auth.username, game_db.psn_id)
						continue

					print "Update User Game |%s| - |%s| - |%s| - |END|" %(updateType, user_db.auth.username, game_db.psn_id)
				#else:
				#	try:
				#		print "Update User Game |%s| - |%s| - |%s| - |NO NEED|" %(updateType, user_db.auth.username, game_db.name)
				#	except:
				#		print "FUUUUCK"
				#		print user_game_db.game.id
				#		pass
		except KeyboardInterrupt:
			print "CTRL+C"
			os._exit(0)
		except:
			x = sys.exc_info() 
			traceback.print_exception(*x)

	if not manual:
		recalcRank()
